#include <cstdio>
#include <cstdlib>
#include <unistd.h> // For usleep()
#include <sstream> // For ostringstream
#include <iomanip>

#include "WupperChecker.h"
#include "WupperReceiver.h"
//#include "crc.h"

// ----------------------------------------------------------------------------

WupperChecker::WupperChecker()
{
  this->reset();
}

// ----------------------------------------------------------------------------

void WupperChecker::reset()
{
  _blocksChecked  = 0;
  errorIndex      = -1;
  _undefBlocks    = 0;
}

// ----------------------------------------------------------------------------

void WupperChecker::checkBlocks( uint64_t startAddress,
                              uint64_t numberOfBytes,
                              int  check_level,
                              bool dump_on_error, int elink_filter,
                              int  blocknr_offs, int blocks_to_skip,
                              bool report_te, bool report_crc )
{
  u_short *block1k_s = (u_short *) startAddress;
  uint8_t *block1k   = (uint8_t *) startAddress;
  
  uint8_t *blockWithError = 0;
  bool     errorFlag = false;
  int      errorCount = 0;
  int      blocks_skipped = 0;



  int blocknr;
  for( blocknr=blocknr_offs;
       blocknr<blocknr_offs + (int)(numberOfBytes/_blockSize); ++blocknr )
    {
      if( blocks_skipped < blocks_to_skip )
        {
          ++blocks_skipped;
          block1k_s = block1k_s + _blockSize/2;
          block1k   = block1k   + _blockSize;
          continue;
        }

      

      // For IDs 0 and 1 these were all the checks, so skip to next block..
      if( check_level == 0 || check_level == 1 )
        {
          block1k_s = block1k_s + _blockSize/2;
          block1k   = block1k   + _blockSize;
          ++_blocksChecked;
          ++_blocksHandled;
          continue;
        }

      

      if( errorFlag )
        {
          ++errorCount;
          if (blockWithError == 0) blockWithError = block1k;
        }

      if( errorFlag && dump_on_error )
        {
          if( blockWithError == 0 ) blockWithError = block1k;

          if( errorIndex > 32 )
            errorIndex -= 32;
          else
            errorIndex = 0;
          this->displayBlock( block1k, blocknr, 64, errorIndex );
        }
      errorFlag = false;

      block1k_s = block1k_s + _blockSize/2;
      block1k   = block1k   + _blockSize;
      ++_blocksChecked;
      ++_blocksHandled;
    }

}



void WupperChecker::displaySummary()
{
  // Display a list of Elinks and info about their (sub)chunks (type, size)
  // compiled while running a data blocks check
  int  elinks_2bit = 0, elinks_4bit = 0, elinks_8bit = 0;//,elinks_16bit = 0;
  int  elinks_24bit = 0, elinks_28bit = 0;
  int  elinks_ttc = 0, elinks_aux = 0, elinks_ic = 0, elinks_ec = 0;
  int  elinks_total = 0;
  bool may_be_fullmode = false;

  long blocks_total = 0;
  
  printf( "Total blocks: %ld", blocks_total );
  if( _undefBlocks > 0 )
    {
      printf( " (+UNDEF %ld)\n", blocks_total + _undefBlocks );
      printf( "### UNDEFINED-HEADER BLOCKS: %ld\n", _undefBlocks );
    }
  else
    {
      printf( "\n" );
    }

  // Display the E-links widths/types as accurate as possible
  printf( "Total number of Elinks %d: width/type", elinks_total );
  if( elinks_2bit > 0 )
    printf( " 2bit:%d",   elinks_2bit );
  if( elinks_4bit > 0 )
    printf( " 4bit:%d",   elinks_4bit );
  if( elinks_8bit > 0 )
    printf( " 8bit:%d",   elinks_8bit );
  if( elinks_28bit > 0 )
    printf( " 2bit|8bit:%d", elinks_28bit );
  if( elinks_24bit > 0 )
    {
      printf( " 2bit|4bit" );
      if( may_be_fullmode )
        printf( "|FULL" );
      printf( ":%d", elinks_24bit );
    }
  if( elinks_ec > 0 )
    printf( " EC:%d", elinks_ec );
  if( elinks_ic > 0 )
    printf( " IC:%d", elinks_ic );
  if( elinks_aux > 0 )
    printf( " AUX:%d", elinks_aux );
  if( elinks_ttc > 0 )
    printf( " TTC2HOST:%d", elinks_ttc );

  int tot = (elinks_2bit + elinks_4bit + elinks_8bit +
             elinks_24bit + elinks_28bit +
             elinks_ttc + elinks_aux + elinks_ic + elinks_ec);
  if( elinks_total - tot != 0 )
    printf( " ###UNKNOWN:%d", elinks_total - tot );
  printf( "\n" );

  if( _truncCount > 0 || _errCount > 0 || _crcerrCount > 0 )
    printf( "Totals error flags: trunc=%ld, err=%ld, crc=%ld\n",
            truncCount(), errCount(), crcerrCount() );
}

// ----------------------------------------------------------------------------
